package alexAI;

import java.util.ArrayList;

public class MinMaxStrategy
{	
	private static MinMaxStrategy instance;
	private int pos = -1;
	private int score = 0;
	private Game game;
	private static int masterCpt = 0;
	private int tmpInt = 0;
	private int[][] bestMove = new int[2][2];
	private int bestScore = 0;
	private int minScore;
	private int maxScore;
	

	
	private MinMaxStrategy()
	{
		game = new Game();
	}

	
	public static int getMasterCpt()
	{
	 return masterCpt;
	}
	
	
	public static MinMaxStrategy getInstance()
	{
		if(instance == null)
		{
				instance = new MinMaxStrategy();
		}
		return instance;
	}
	
	
	
	public void resetPos()
	{
		pos = -1;
	}
	
	public int negamax(int depth, boolean white, int alpha, int beta, int player)
	{
		//pos++;
		if(depth == 0)
		{
		 //GameUtils.printBoard(game.getBoard());
		 masterCpt++;
			return 50;
		}
		else
		{
			int score = -100;
			int max = -100;
			ArrayList<int[][]> moves = game.getAllValidMoves(white);
			for (int i = 0; i < moves.size(); i++)
			{
				game.doMove(moves.get(i));
				score = 0;
				
			//	LogPush.getInstance().storeFilePusherLine(game.getBoard(), moves.get(i));
				
			
				int val = -negamax(depth-1, !white, 0, 0, 1);
				game.undoMove(moves.get(i));
			}
			return pos;
		}
		//return -1; //TWITCHY TAIL DANGER
	}
	
	
	
	public int negamax2(int depth, boolean isWhite, int alpha, int beta, int color)
 {
  //pos++;
  if(depth == 0)
  {
   tmpInt = AI.evalBoard(game.getBoard(), isWhite);
   LogPush.getInstance().writeToFile(Integer.toString(tmpInt));
   
   LogPush.getInstance().writeToFile(LogPush.getInstance().getBoard(game.getBoard()));
   masterCpt++;
   return tmpInt;
  }
  else
  {
   score = -10000;
   ArrayList<int[][]> moves = GameUtils.getAllValidMoves(game.getBoard(), isWhite);
   for (int i = 0; i < moves.size(); i++)
   {
    game.doMove(moves.get(i));
    
  //  LogPush.getInstance().storeFilePusherLine(game.getBoard(), moves.get(i));
    
   
    score = Math.max(score, -negamax2(depth-1, !isWhite, 0, 0, 1));
    game.undoMove(moves.get(i));
   }
   return score;
  }
  //return -1; //TWITCHY TAIL DANGER
 }
	
	
	public int minimax2(int[][] board, boolean isWhite, int depth, int maxDepth)
 {
  //pos++;
  if (depth == maxDepth)
  {
   tmpInt = AI.evalBoard(board, isWhite);
   LogPush.getInstance().writeToFile(Integer.toString(tmpInt));
   LogPush.getInstance().writeToFileNewLine();
  // LogPush.getInstance().writeToFile(LogPush.getInstance().getBoard(board));
   masterCpt++;
   return tmpInt;
  }
  
  bestMove = null;
  
  if (depth != 0) // HANDELING THE CHANGE OF PLAYER, ALL ABOARD THE FAILTRAIN TO FAILLAND
  {
   if (isWhite == true){isWhite = false;}else{isWhite = true;}
  }
  
  if (isWhite){bestScore = -10000;} // White playing
  else{bestScore = 10000;} // Black Playing
  
  ArrayList<int[][]> moves = GameUtils.getAllValidMoves(board, isWhite);
  for (int i = 0; i < moves.size(); i++)
  {
   int[][] newBoard = GameUtils.copyBoard(board);
   newBoard = GameUtils.doMove(newBoard, moves.get(i));
   score = minimax2(newBoard, isWhite, depth+1, maxDepth);
   if (isWhite) // playing white
   {
    
    if (score > bestScore) // new best score!
    {
     bestScore = score;
     if (bestScore == 20){System.out.println("ding ding ding");}
     bestMove = moves.get(i);
    }
   }
   else // playing black
   {
    if (score < bestScore) // new worst score!
    {
     bestScore = score;
     bestMove = moves.get(i);
    }
   }
  }
  
  return bestScore;
 }
	
	
	
	/**
	 * 
	 * @param board ; the board to eval
	 * @param player boolean ; whose turn it is, TRUE = WHITE     ----    FALSE = BLACK
	 * @param depth int ; What ply is the algo at 
	 * @param maxDepth int ; How many plies we should do
	 * @param whoToMax boolean ; who is MAX,     TRUE = WHITE     ----    FALSE = BLACK
	 * @return
	 */
	public int minimaxprof(int[][] board, boolean player, int depth, int maxDepth, boolean whoToMax)
 {
	 
  //pos++;
  if (depth == maxDepth)
  {
   if (player){System.out.print("depth is " + depth + " | evaluating board as white: ");}
   else{System.out.print("depth is " + depth + " | evaluating board as black: ");}
   
   tmpInt = AI.evalBoard(board, !player); // why the !.. ask Alex it's tricky =/
   System.out.println(tmpInt);
   LogPush.getInstance().writeToFile(Integer.toString(tmpInt));
   LogPush.getInstance().writeToFileNewLine();
   LogPush.getInstance().writeToFile(LogPush.getInstance().getBoard(board));
   masterCpt++;
   return tmpInt;
  }
  
  bestMove = null;
  /*
  if (depth != 0) // HANDELING THE CHANGE OF PLAYER, ALL ABOARD THE FAILTRAIN TO FAILLAND
  {
   if (player == true){player = false;}else{player = true;}
  }
  */
  if (whoToMax == player) // Will execute if it's the MAX player turn to play
  {
   maxScore = -10000;
   ArrayList<int[][]> moves = GameUtils.getAllValidMoves(board, player);
   for (int i = 0; i < moves.size(); i++)
   {
    int[][] newBoard = GameUtils.copyBoard(board);
    newBoard = GameUtils.doMove(newBoard, moves.get(i));
    score = minimaxprof(newBoard, false, depth+1, maxDepth, whoToMax);
    maxScore = Math.max(maxScore, score);
   }
   return maxScore;
  }
  else // Will execute if it's the MIN player turn to play
  {
   minScore = 10000;
   ArrayList<int[][]> moves = GameUtils.getAllValidMoves(board, player);
   for (int i = 0; i < moves.size(); i++)
   {
    int[][] newBoard = GameUtils.copyBoard(board);
    newBoard = GameUtils.doMove(newBoard, moves.get(i));
    score = minimaxprof(newBoard, true, depth+1, maxDepth, whoToMax);
    minScore = Math.min(minScore, score);
   }
   return minScore;
  }
 }
	
	
	
	
	
	public int miniminimaxprof(int[][] board, boolean player, int depth, int maxDepth, boolean whoToMax)
 {
  
  //pos++;
  if (depth == maxDepth)
  {
   if (player){System.out.print("depth is " + depth + " | evaluating board as black: ");}
   else{System.out.print("depth is " + depth + " | evaluating board as white: ");}
   
   tmpInt = AI.evalMiniBoard(board, !player); // why the !.. ask Alex it's tricky =/
   System.out.println(tmpInt);
   LogPush.getInstance().writeToFile(Integer.toString(tmpInt));
   LogPush.getInstance().writeToFileNewLine();
   LogPush.getInstance().writeToFile(LogPush.getInstance().getMiniBoard(board));
   masterCpt++;
   return tmpInt;
  }
  
  bestMove = null;
  /*
  if (depth != 0) // HANDELING THE CHANGE OF PLAYER, ALL ABOARD THE FAILTRAIN TO FAILLAND
  {
   if (player == true){player = false;}else{player = true;}
  }
  */
  
  //GameUtils.printMiniBoard(board);
  if (whoToMax == player) // Will execute if it's the MAX player turn to play
  {
   maxScore = -10000;
   ArrayList<int[][]> moves = GameUtils.getAllValidMiniMoves(board, player);
   if (depth == (maxDepth-1)){
    System.out.println("");
    GameUtils.printMiniBoard(board);
   }
   //System.out.println("dept: " + depth);
   for (int i = 0; i < moves.size(); i++)
   {
    int[][] newBoard = GameUtils.copyMiniBoard(board);
    newBoard = GameUtils.doMiniMove(newBoard, moves.get(i));
    score = miniminimaxprof(newBoard, false, depth+1, maxDepth, whoToMax);
    maxScore = Math.max(maxScore, score);
   }
//   System.out.println("POUT" + maxScore);
   return maxScore;
  }
  else // Will execute if it's the MIN player turn to play
  {
   minScore = 10000;
   ArrayList<int[][]> moves = GameUtils.getAllValidMiniMoves(board, player);
   if (depth == (maxDepth-1)){
    System.out.println("");
    GameUtils.printMiniBoard(board);
   }
   for (int i = 0; i < moves.size(); i++)
   {
    int[][] newBoard = GameUtils.copyMiniBoard(board);
    newBoard = GameUtils.doMiniMove(newBoard, moves.get(i));
    score = miniminimaxprof(newBoard, true, depth+1, maxDepth, whoToMax);
    minScore = Math.min(minScore, score);
   }
   return minScore;
  }
 }
	
	
	
	
	
	
	public int miniminimax(int[][] board, boolean isWhite, int depth, int maxDepth)
 {
  //pos++;
  if (depth == maxDepth)
  {
   tmpInt = AI.evalMiniBoard(board, isWhite);
  // LogPush.getInstance().writeToFile(Integer.toString(tmpInt));
   
  // LogPush.getInstance().writeToFile(LogPush.getInstance().getBoard(board));
   masterCpt++;
   return tmpInt;
  }
  
  bestMove = null;
  
  if (depth != 0) // HANDELING THE CHANGE OF PLAYER, ALL ABOARD THE FAILTRAIN TO FAILLAND
  {
   if (isWhite == true){isWhite = false;}else{isWhite = true;}
  }
  
  if (isWhite){bestScore = -10000;} // White playing
  else{bestScore = 10000;} // Black Playing
  
  ArrayList<int[][]> moves = GameUtils.getAllValidMiniMoves(board, isWhite);
  
  for (int i = 0 ; i < moves.size(); i++)
  {
   System.out.println("hello?");
   LogPush.getInstance().printConsoleMiniMove(moves.get(i));
  }
  
 // System.out.println("Batard d'enfant stupide");
  for (int i = 0; i < moves.size(); i++)
  {
   int[][] newBoard = GameUtils.copyMiniBoard(board);
   newBoard = GameUtils.doMiniMove(newBoard, moves.get(i));
  // System.out.println("Batard d'enfant stupide");
   score = miniminimax(newBoard, isWhite, depth+1, maxDepth);
   if (isWhite) // playing white
   {
    if (score > bestScore) // new best score!
    {
     bestScore = score;
     bestMove = moves.get(i);
    }
   }
   else // playing black
   {
    if (score < bestScore) // new worst score!
    {
     bestScore = score;
     bestMove = moves.get(i);
    }
   }
  }
  
  return bestScore;
 }
	
	
	
	/*
	
	public int negamax3(int[][] board, depth)
 {
  //pos++;
  if(depth == 0)
  {
   tmpInt = game.evalBoard(isWhite);
   System.out.println(tmpInt);
   GameUtils.printBoard(game.getBoard());
   return tmpInt;
  }
  else
  {
   score = -10000;
   ArrayList<int[][]> moves = GameUtils.getAllValidMoves(game.getBoard(), isWhite);
   for (int i = 0; i < moves.size(); i++)
   {
    game.doMove(moves.get(i));
    
    LogPush.getInstance().storeFilePusherLine(game.getBoard(), moves.get(i));
    masterCpt++;
   
    score = Math.max(score, -negamax2(depth-1, !isWhite, 0, 0, 1));
    game.undoMove(moves.get(i));
   }
   return score;
  }
  //return -1; //TWITCHY TAIL DANGER
 }*/
}
